﻿// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Http.Resilience.Internal;
using Microsoft.Extensions.ObjectPool;
using Microsoft.Shared.Diagnostics;

namespace Microsoft.Extensions.Http.Resilience.Routing.Internal.OrderedGroups;

internal sealed class OrderedGroupsRoutingStrategy : RequestRoutingStrategy, IResettable
{
    private readonly ObjectPool<OrderedGroupsRoutingStrategy> _pool;
    private int _lastUsedIndex;
    private IList<UriEndpointGroup>? _groups;

    public OrderedGroupsRoutingStrategy(Randomizer randomizer, ObjectPool<OrderedGroupsRoutingStrategy> pool)
        : base(randomizer)
    {
        _pool = pool;
    }

    public void Initialize(IList<UriEndpointGroup> groups)
    {
        _ = TryReset();

        _groups = groups;
    }

    public override bool TryGetNextRoute([NotNullWhen(true)] out Uri? nextRoute)
    {
        if (_groups == null)
        {
            Throw.InvalidOperationException("The routing strategy is not initialized.");
        }

        if (TryGetNextGroup(out var group))
        {
            nextRoute = group!.Endpoints.SelectByWeight(e => e.Weight, Randomizer!).Uri!;
            return true;
        }

        nextRoute = null;
        return false;
    }

    public override void Dispose() => _pool.Return(this);

    public override bool TryReset()
    {
        _groups = null;
        _lastUsedIndex = 0;
        return true;
    }

    private bool TryGetNextGroup(out UriEndpointGroup? nextGroup)
    {
        if (_lastUsedIndex >= _groups!.Count)
        {
            nextGroup = null;
            return false;
        }

        nextGroup = _groups[_lastUsedIndex];
        _lastUsedIndex++;
        return true;
    }
}
